<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha256-Z1K5uhUaJXA7Ll0XrZ/0JhX4lAtZFpT6jkKrEDT0drU=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"example.com","root":"/","images":"/images","scheme":"Muse","darkmode":false,"version":"8.14.1","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":-1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="进程&#x2F;线程相关线程相关background information线程和进程的理论概念不再赘述。Linux 中，系统是不认识线程还是进程的，它只认识 task。  下面的阐述都是 Unix like 下的有关线程的语义。  主线程和子线程  共享： 用户区内，除了栈区是不共享的，其余都是共享的。 不共享： 栈区（当有 1 主 + 4 子线程时候，栈区会被平分为 5 份）  多进程共享的资">
<meta property="og:type" content="article">
<meta property="og:title" content="Linux多进程、多线程编程">
<meta property="og:url" content="http://example.com/2021/11/20/Linux%E5%A4%9A%E8%BF%9B%E7%A8%8B%E3%80%81%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%BC%96%E7%A8%8B/index.html">
<meta property="og:site_name" content="JsyBlog">
<meta property="og:description" content="进程&#x2F;线程相关线程相关background information线程和进程的理论概念不再赘述。Linux 中，系统是不认识线程还是进程的，它只认识 task。  下面的阐述都是 Unix like 下的有关线程的语义。  主线程和子线程  共享： 用户区内，除了栈区是不共享的，其余都是共享的。 不共享： 栈区（当有 1 主 + 4 子线程时候，栈区会被平分为 5 份）  多进程共享的资">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2021-11-20T14:13:12.000Z">
<meta property="article:modified_time" content="2022-03-28T07:28:06.160Z">
<meta property="article:author" content="SongyangJi">
<meta property="article:tag" content="C">
<meta property="article:tag" content="Linux">
<meta property="article:tag" content="进程">
<meta property="article:tag" content="线程">
<meta name="twitter:card" content="summary">


<link rel="canonical" href="http://example.com/2021/11/20/Linux%E5%A4%9A%E8%BF%9B%E7%A8%8B%E3%80%81%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%BC%96%E7%A8%8B/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"http://example.com/2021/11/20/Linux%E5%A4%9A%E8%BF%9B%E7%A8%8B%E3%80%81%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%BC%96%E7%A8%8B/","path":"2021/11/20/Linux多进程、多线程编程/","title":"Linux多进程、多线程编程"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>Linux多进程、多线程编程 | JsyBlog</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">JsyBlog</p>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E8%BF%9B%E7%A8%8B-x2F-%E7%BA%BF%E7%A8%8B%E7%9B%B8%E5%85%B3"><span class="nav-number">1.</span> <span class="nav-text">进程&#x2F;线程相关</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BA%BF%E7%A8%8B%E7%9B%B8%E5%85%B3"><span class="nav-number">1.1.</span> <span class="nav-text">线程相关</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#background-information"><span class="nav-number">1.2.</span> <span class="nav-text">background information</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#pthread-create"><span class="nav-number">1.2.1.</span> <span class="nav-text">pthread_create</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#pthread-join"><span class="nav-number">1.2.2.</span> <span class="nav-text">pthread_join</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#pthread-detach"><span class="nav-number">1.2.3.</span> <span class="nav-text">pthread_detach</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#pthread-cancel"><span class="nav-number">1.2.4.</span> <span class="nav-text">pthread_cancel</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BF%A1%E5%8F%B7%E5%A4%84%E7%90%86%E7%9B%B8%E5%85%B3"><span class="nav-number">1.3.</span> <span class="nav-text">信号处理相关</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#raise"><span class="nav-number">1.3.1.</span> <span class="nav-text">raise</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#signal"><span class="nav-number">1.3.2.</span> <span class="nav-text">signal</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#sandbox%E4%BD%BF%E7%94%A8%E7%9A%84%E4%BF%A1%E5%8F%B7"><span class="nav-number">1.3.3.</span> <span class="nav-text">sandbox使用的信号</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#SIGUSR1-x2F-SIGUSR2"><span class="nav-number">1.3.4.</span> <span class="nav-text">SIGUSR1&#x2F;SIGUSR2</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#SIGSEGV"><span class="nav-number">1.3.5.</span> <span class="nav-text">SIGSEGV</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#execXX-%E5%87%BD%E6%95%B0%E7%BB%84"><span class="nav-number">1.4.</span> <span class="nav-text">execXX 函数组</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#execve"><span class="nav-number">1.4.1.</span> <span class="nav-text">execve</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#sleep"><span class="nav-number">1.4.2.</span> <span class="nav-text">sleep</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#wait-%E5%87%BD%E6%95%B0%E7%BB%84"><span class="nav-number">1.5.</span> <span class="nav-text">wait 函数组</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#wait"><span class="nav-number">1.5.1.</span> <span class="nav-text">wait</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#waitpid"><span class="nav-number">1.5.2.</span> <span class="nav-text">waitpid</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#wait3-x2F-wait4"><span class="nav-number">1.5.3.</span> <span class="nav-text">wait3&#x2F;wait4</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8int-status"><span class="nav-number">1.5.4.</span> <span class="nav-text">如何使用int* status</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#WIFEXITED-int-status"><span class="nav-number">1.5.5.</span> <span class="nav-text">WIFEXITED(int status)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#WEXITSTATUS-status"><span class="nav-number">1.5.6.</span> <span class="nav-text">WEXITSTATUS(status)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#WIFSIGNALED-status"><span class="nav-number">1.5.7.</span> <span class="nav-text">WIFSIGNALED(status)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link"><span class="nav-number">1.5.8.</span> <span class="nav-text"></span></a></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">SongyangJi</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">251</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">45</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">109</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/11/20/Linux%E5%A4%9A%E8%BF%9B%E7%A8%8B%E3%80%81%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%BC%96%E7%A8%8B/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="Linux多进程、多线程编程 | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Linux多进程、多线程编程
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-11-20 22:13:12" itemprop="dateCreated datePublished" datetime="2021-11-20T22:13:12+08:00">2021-11-20</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2022-03-28 15:28:06" itemprop="dateModified" datetime="2022-03-28T15:28:06+08:00">2022-03-28</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Linux/" itemprop="url" rel="index"><span itemprop="name">Linux</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <h1 id="进程-x2F-线程相关"><a href="#进程-x2F-线程相关" class="headerlink" title="进程&#x2F;线程相关"></a>进程&#x2F;线程相关</h1><h2 id="线程相关"><a href="#线程相关" class="headerlink" title="线程相关"></a>线程相关</h2><h2 id="background-information"><a href="#background-information" class="headerlink" title="background information"></a>background information</h2><p>线程和进程的理论概念不再赘述。<br>Linux 中，系统是不认识线程还是进程的，它只认识 task。</p>
<blockquote>
<p>下面的阐述都是 Unix like 下的有关线程的语义。</p>
</blockquote>
<p>主线程和子线程</p>
<ul>
<li>共享： 用户区内，除了栈区是不共享的，其余都是共享的。</li>
<li>不共享： 栈区（当有 1 主 + 4 子线程时候，栈区会被平分为 5 份）</li>
</ul>
<p>多进程共享的资源（fork、clone出的子进程和父进程）：</p>
<ul>
<li>代码</li>
<li>文件描述符</li>
<li>内存映射区 –mmap</li>
</ul>
<p>多线程共享的资源：</p>
<ul>
<li><p>堆</p>
</li>
<li><p>全局变量 </p>
</li>
<li><p>线程号和线程 ID 是有区别的<br>查看方式： 找到程序的进程 ID后， <code>ps -Lf $(pid)</code>，LWP那一列即为线程ID。</p>
</li>
</ul>
<h3 id="pthread-create"><a href="#pthread-create" class="headerlink" title="pthread_create"></a>pthread_create</h3><ul>
<li><p>头文件:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;pthread.h&gt;</span></span></span><br></pre></td></tr></table></figure>
<p>pthread非linux系统的默认库， 需手动链接-线程库 -lpthread</p>
</li>
<li><p>函数说明:<br>返回成功时，由 tidp 指向的内存单元被设置为新创建线程的线程ID。a<br>ttr参数用于指定各种不同的线程属性。<br>新创建的线程从start_rtn函数的地址开始运行，该函数只有一个万能指针参数arg。<br>如果需要向start_rtn函数传递的参数不止一个，那么需要把这些参数放到一个结构体中，然后把这个结构的地址作为arg的参数传入。</p>
</li>
<li><p>函数定义</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">pthread_create</span><span class="params">(<span class="type">pthread_t</span> *tidp,<span class="type">const</span> <span class="type">pthread_attr_t</span> *attr, <span class="type">void</span> *(*start_rtn)(<span class="type">void</span>*),<span class="type">void</span> *arg)</span>;</span><br></pre></td></tr></table></figure>


</li>
<li><p>参数说明：<br>第一个参数为指向线程标识符的指针。<br>第二个参数用来设置线程属性。<br>第三个参数是线程运行函数的起始地址。<br>最后一个参数是运行函数的参数。</p>
</li>
<li><p>返回值<br>若线程创建成功，则返回0。若线程创建失败，则返回出错编号，并且*thread中的内容是未定义的。</p>
</li>
<li><p>代码</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> num = <span class="number">13</span>; <span class="comment">//设置为全局变量，在全局区域，共享</span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span>* <span class="title function_">myfun</span><span class="params">(<span class="type">void</span>* arg)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">void</span>* p = (<span class="type">void</span> *)&amp;num;  <span class="comment">//传一个地址进去（voi* 也是 4 个字节）</span></span><br><span class="line">    <span class="type">pthread_t</span> id[<span class="number">5</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">        pthread_create(&amp;(id[i]), <span class="literal">NULL</span>, myfun, p);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;i = %d, thread id: %ld\n&quot;</span>, i, id[i]);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span>* <span class="title function_">myfun</span><span class="params">(<span class="type">void</span>* arg)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;num = %d, child thread id: %ld\n&quot;</span>, (*((<span class="type">int</span> *)arg))++, pthread_self());</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>参考链接<br><a target="_blank" rel="noopener" href="https://man7.org/linux/man-pages/man3/pthread_create.3.html">pthread_create(3) — Linux manual page</a><br><a target="_blank" rel="noopener" href="https://xmuli.tech/posts/28f8209f/">Linux中创建多线程实例pthread_create()</a></p>
</li>
</ul>
<h3 id="pthread-join"><a href="#pthread-join" class="headerlink" title="pthread_join"></a>pthread_join</h3><p>pthread_join()即是子线程合入主线程，主线程阻塞等待子线程结束，然后回收子线程资源。</p>
<p>注意，默认情况下，资源是不会随着子线程的exit或return而回收的。</p>
<ul>
<li><p>头文件:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>函数说明:<br>thread_join()函数，以阻塞的方式等待thread指定的线程结束。当函数返回时，被等待线程的资源被收回。<br>如果线程已经结束，那么该函数会立即返回。并且thread指定的线程必须是 joinable 的。</p>
</li>
<li><p>函数定义</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">pthread_join</span><span class="params">(<span class="type">pthread_t</span> thread, <span class="type">void</span> **retval)</span>;</span><br></pre></td></tr></table></figure>
<p>thread: 线程标识符，即线程ID，标识唯一线程。<br>retval: 用户定义的指针，用来存储被等待线程的返回值。</p>
</li>
<li><p>返回值<br>0代表成功。 失败，返回的则是错误号。</p>
</li>
<li><p>示例代码：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *<span class="title function_">thread_function</span><span class="params">(<span class="type">void</span> *arg)</span> &#123;</span><br><span class="line">    <span class="type">int</span> i;</span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">8</span>; i++) &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Thread working... %d \n&quot;</span>, i);</span><br><span class="line">        sleep(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">    <span class="type">pthread_t</span> mythread;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (pthread_create(&amp;mythread, <span class="literal">NULL</span>, thread_function, <span class="literal">NULL</span>)) &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;error creating thread.&quot;</span>);</span><br><span class="line">        <span class="built_in">abort</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (pthread_join(mythread, <span class="literal">NULL</span>)) &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;error join thread.&quot;</span>);</span><br><span class="line">        <span class="built_in">abort</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;thread done! \n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> 输出</span></span><br><span class="line"><span class="comment">Thread working...! 0 </span></span><br><span class="line"><span class="comment">Thread working...! 1 </span></span><br><span class="line"><span class="comment">Thread working...! 2 </span></span><br><span class="line"><span class="comment">Thread working...! 3 </span></span><br><span class="line"><span class="comment">Thread working...! 4 </span></span><br><span class="line"><span class="comment">Thread working...! 5 </span></span><br><span class="line"><span class="comment">Thread working...! 6 </span></span><br><span class="line"><span class="comment">Thread working...! 7 </span></span><br><span class="line"><span class="comment">thread done! </span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure></li>
</ul>
<p>如果去掉<code>pthread_join</code>的调用的话，<br>输出为：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">thread done! </span><br><span class="line">Thread working... 0 </span><br><span class="line">Process finished with exit code 0</span><br></pre></td></tr></table></figure>
<p>也就是说，子线程来不及执行它的函数，就因为父线程的死亡而被迫终结了。</p>
<h3 id="pthread-detach"><a href="#pthread-detach" class="headerlink" title="pthread_detach"></a>pthread_detach</h3><ul>
<li><p>头文件:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>函数说明:<br>pthread_join()函数的替代函数，可回收创建时detachstate属性设置为PTHREAD_CREATE_JOINABLE的线程的存储空间。<br>该函数不会阻塞父线程。<br>pthread_join()函数用于只是应用程序在线程tid终止时回收其存储空间。</p>
</li>
<li><p>函数定义</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">pthread_detach</span><span class="params">(<span class="type">pthread_t</span> tid)</span>;</span><br></pre></td></tr></table></figure>
</li>
<li><p>返回值<br>thread_detach() 在调用成功完成之后返回零。其他任何返回值都表示出现了错误。</p>
</li>
</ul>
<p>注意，即使如此，父线程退出时，子线程仍然会强制退出。</p>
<h3 id="pthread-cancel"><a href="#pthread-cancel" class="headerlink" title="pthread_cancel"></a>pthread_cancel</h3><ul>
<li><p>函数说明：<br>发送终止信号给thread线程，如果成功则返回0，否则为非0值。发送成功并不意味着thread会终止。</p>
</li>
<li><p>函数定义：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">pthread_cancel</span><span class="params">(<span class="type">pthread_t</span> thread)</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>示例代码：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @Author: 吉松阳</span></span><br><span class="line"><span class="comment"> * @Date: 2021/9/26</span></span><br><span class="line"><span class="comment"> * @Description: </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pthread.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">print_message_function</span><span class="params">(<span class="type">void</span> *ptr)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">pthread_t</span> thread1;</span><br><span class="line">    pthread_create(&amp;thread1, <span class="literal">NULL</span>, (<span class="type">void</span> *) &amp;print_message_function, (<span class="type">void</span> *) <span class="number">0</span>);</span><br><span class="line">    sleep(<span class="number">3</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;main thread\n&quot;</span>);</span><br><span class="line">    pthread_cancel(thread1);</span><br><span class="line">    sleep(<span class="number">7</span>);</span><br><span class="line">    <span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">print_message_function</span><span class="params">(<span class="type">void</span> *ptr)</span> &#123;</span><br><span class="line">    pthread_detach(pthread_self());</span><br><span class="line">    sleep(<span class="number">6</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;child thread\n&quot;</span>);</span><br><span class="line">    pthread_exit(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 实验证明 pthread_exit 确实起作用了</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>参考链接：<br><a target="_blank" rel="noopener" href="https://www.cnblogs.com/lijunamneg/archive/2013/01/25/2877211.html">线程取消(pthread_cancel)</a></p>
</li>
</ul>
<h2 id="信号处理相关"><a href="#信号处理相关" class="headerlink" title="信号处理相关"></a>信号处理相关</h2><h3 id="raise"><a href="#raise" class="headerlink" title="raise"></a>raise</h3><ul>
<li><p>头文件:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>函数说明:<br>C 库函数, 会促使生成信号 sig。sig 参数与 SIG 宏兼容。</p>
</li>
<li><p>函数定义</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// sig -- 要发送的信号码。</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">raise</span><span class="params">(<span class="type">int</span> sig)</span></span><br></pre></td></tr></table></figure></li>
</ul>
<p>查看所有信号：使用 <code>kill -l</code></p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">songyangji@SongyangJi-Ubuntu-DeskStop:~$ kill -l</span><br><span class="line"> 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP</span><br><span class="line"> 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1</span><br><span class="line">11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM</span><br><span class="line">16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP</span><br><span class="line">21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ</span><br><span class="line">26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR</span><br><span class="line">31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3</span><br><span class="line">38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8</span><br><span class="line">43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13</span><br><span class="line">48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12</span><br><span class="line">53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7</span><br><span class="line">58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2</span><br></pre></td></tr></table></figure>

<p>值得注意的是，<br>当一个进程调用fork时，因为子进程在开始时复制父进程的存储映像，信号捕捉函数的地址在子进程中是有意义的，所以子进程继承父进程的信号处理方式。<br>但是当子进程调用exec后，因为exec运行新的程序后会覆盖从父进程继承来的存储映像。<br>那么信号捕捉函数在新程序中已无意义，所以exec会将原先设置为要捕捉的信号都更改为默认动作。</p>
<ul>
<li>返回值<br>如果成功该函数返回零，否则返回非零。</li>
</ul>
<h3 id="signal"><a href="#signal" class="headerlink" title="signal"></a>signal</h3><ul>
<li><p>头文件:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br></pre></td></tr></table></figure>

</li>
<li><p>函数说明:<br>C 库函数,设置一个函数来处理信号，即带有 sig 参数的信号处理程序。</p>
</li>
<li><p>函数定义</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> (*signal(<span class="type">int</span> sig, <span class="type">void</span> (*func)(<span class="type">int</span>)))(<span class="type">int</span>)</span><br></pre></td></tr></table></figure></li>
</ul>
<p>参数说明：</p>
<ul>
<li><p>sig – 在信号处理程序中作为变量使用的信号码。下面是一些重要的标准信号常量</p>
</li>
<li><p>func – 一个指向函数的指针。它可以是一个由程序定义的函数，也可以是下面预定义函数之一。</p>
<ul>
<li>SIG_DFL	默认的信号处理程序。</li>
<li>SIG_IGN	忽视信号。</li>
</ul>
</li>
<li><p>返回值<br>该函数返回之前的信号处理程序</p>
</li>
<li><p>实例代码</p>
</li>
</ul>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">signal_catchfunc</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">int</span> ret;</span><br><span class="line">    signal(SIGINT, signal_catchfunc);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;开始生成一个信号\n&quot;</span>);</span><br><span class="line">    ret = raise(SIGINT);</span><br><span class="line">    <span class="keyword">if</span> (ret != <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;错误，不能生成SIGINT信号\n&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;退出....\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">signal_catchfunc</span><span class="params">(<span class="type">int</span> signal)</span> &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;捕获信号\n&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="sandbox使用的信号"><a href="#sandbox使用的信号" class="headerlink" title="sandbox使用的信号"></a>sandbox使用的信号</h3><p>信号的共达60余个，这里只介绍一下sandbox中使用的信号。</p>
<h3 id="SIGUSR1-x2F-SIGUSR2"><a href="#SIGUSR1-x2F-SIGUSR2" class="headerlink" title="SIGUSR1&#x2F;SIGUSR2"></a>SIGUSR1&#x2F;SIGUSR2</h3><p>SIGUSR1 用户自定义信号 默认处理：进程终止;<br>SIGUSR2 用户自定义信号默认处理：进程终止。</p>
<h3 id="SIGSEGV"><a href="#SIGSEGV" class="headerlink" title="SIGSEGV"></a>SIGSEGV</h3><p>在POSIX兼容的平台上，SIGSEGV是当一个进程<strong>执行了一个无效的内存引用</strong>，或<strong>发生段错误</strong>时发送给它的信号。<br>SIGSEGV的符号常量在头文件<code>signal.h</code>中定义。<br>因为在不同平台上，信号数字可能变化，因此最好使用符号信号名。通常，它是信号#11。<br><a target="_blank" rel="noopener" href="https://zh.wikipedia.org/wiki/SIGSEGV">SIGSEGV维基百科</a></p>
<h2 id="execXX-函数组"><a href="#execXX-函数组" class="headerlink" title="execXX 函数组"></a>execXX 函数组</h2><p>exec函数族提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件，<br>并用它来取代原调用进程的数据段、代码段和堆栈段，在执行完之后，原调用进程的内容除了进程号外，其他全部被新的进程替换了。<br>另外，这里的可执行文件既可以是二进制文件，也可以是Linux下任何可执行的脚本文件。</p>
<p>exec函数一共有六个，其中execve为内核级系统调用，<br>其他（execl，execle，execlp，execv，execvp）都是调用execve的库函数。<br>不同之处在于如何找到程序、如何指定参数以及环境来自何处。</p>
<ul>
<li><p>名称中带有 v 的调用，用带有一个数组参数来指定argv[]新程序的数组。数组的最后一个元素为 NULL。</p>
</li>
<li><p>名称中带有 l 的调用，将新程序的参数作为函数本身的可变长度参数列表。参数的结尾为参数指针(char *)NULL。<br>你应该始终进行类型转换，因为NULL实际是整数常量，并且调用可变参数函数时的默认参数转换不会将其转换为指针。</p>
</li>
<li><p>名称中带有 e 的调用，需要一个额外的参数（或l情况下的参数）来提供新程序的环境；否则，程序将继承当前进程的环境。</p>
</li>
</ul>
<h3 id="execve"><a href="#execve" class="headerlink" title="execve"></a>execve</h3><ul>
<li><p>头文件:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>函数说明:<br>pthread_create是类Unix操作系统（Unix、Linux、Mac OS X等）的创建线程的函数。<br>它的功能是创建线程（实际上就是确定调用该线程函数的入口点），在线程创建以后，就开始运行相关的线程函数。</p>
</li>
<li><p>函数定义:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">execve</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *pathname, <span class="type">char</span> *<span class="type">const</span> argv[], <span class="type">char</span> *<span class="type">const</span> envp[])</span>;</span><br></pre></td></tr></table></figure>
</li>
<li><p>返回值:<br>如果执行成功则函数不会返回(后面的代码也并不会执行了)，执行失败则直接返回-1，失败原因存于errno 中。</p>
</li>
<li><p>示例代码:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @Author: 吉松阳</span></span><br><span class="line"><span class="comment"> * @Date: 2021/9/22</span></span><br><span class="line"><span class="comment"> * @Description: </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">char</span> *argv[] = &#123;<span class="string">&quot;ls&quot;</span>, <span class="string">&quot;-el&quot;</span>, <span class="literal">NULL</span>&#125;;</span><br><span class="line">    <span class="type">char</span> *envp[] = &#123;<span class="string">&quot;PATH=/bin&quot;</span>, <span class="number">0</span>&#125;;</span><br><span class="line">    execve(<span class="string">&quot;/bin/ls&quot;</span>, argv, envp);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">  total 128</span></span><br><span class="line"><span class="comment">  drwxr-xr-x  5 jisongyang  staff    160 Sep 22 22:07 CMakeFiles</span></span><br><span class="line"><span class="comment">  -rw-r--r--  1 jisongyang  staff   6687 Sep 22 22:06 Makefile</span></span><br><span class="line"><span class="comment">  -rw-r--r--  1 jisongyang  staff   1021 Sep 22 22:06 cmake_install.cmake</span></span><br><span class="line"><span class="comment">  -rwxr-xr-x  1 jisongyang  staff  50424 Sep 22 22:22 test_execve</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure></li>
</ul>
<p>参考链接:</p>
<ol>
<li><a target="_blank" rel="noopener" href="https://man7.org/linux/man-pages/man2/execve.2.html">execve(2) — Linux manual page</a></li>
<li><a target="_blank" rel="noopener" href="https://stackoverflow.com/questions/20823371/what-is-the-difference-between-the-functions-of-the-exec-family-of-system-calls">What is the difference between the functions of the exec family of system calls like exec and execve?</a></li>
</ol>
<h3 id="sleep"><a href="#sleep" class="headerlink" title="sleep"></a>sleep</h3><ul>
<li><p>头文件:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>函数说明:<br>sleep()会令目前的进程暂停, 直到达到参数seconds 所指定的时间, 或是被信号所中断.</p>
</li>
<li><p>函数定义</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">sleep</span><span class="params">(<span class="type">unsigned</span> <span class="type">int</span> seconds)</span>;</span><br></pre></td></tr></table></figure>
</li>
<li><p>返回值<br>若进程暂停到参数seconds 所指定的时间则返回0, 若有信号中断则返回剩余秒数.</p>
</li>
</ul>
<h2 id="wait-函数组"><a href="#wait-函数组" class="headerlink" title="wait 函数组"></a>wait 函数组</h2><p>进程调用 exit() 退出执行后，被设置为僵死状态。<br>这时父进程可以通过 wait4() 系统调用查询子进程是否终结，之后再进行最后的操作，彻底删除进程所占用的内存资源。<br>wait4() 系统调用由 linux 内核实现。<br>linux 系统通常提供了 wait()、waitpid()、wait3()、wait4() 这四个函数，<br>四个函数的参数不同，语义也有细微的差别，但是都返回关于终止进程的状态信息。</p>
<h3 id="wait"><a href="#wait" class="headerlink" title="wait"></a>wait</h3><ul>
<li><p>头文件:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span>        <span class="comment">// 提供类型 pid_t 的定义</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/wait.h&gt;</span></span></span><br></pre></td></tr></table></figure>
</li>
<li><p>函数说明:<br>当进程调用 wait() 时，会暂停目前进程的执行（即阻塞），由 wait() 来自动分析是否当前进程的某个子进程已经退出，<br>如果找到了这样一个已经变成僵尸进程的子进程，wait 就会收集这个子进程的信息，并将其彻底销毁后返回；<br>如果没有找到这样一个子进程，wait 就会一直阻塞在这里，直到出现<strong>僵尸进程</strong>。</p>
</li>
<li><p>函数定义</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">pid_t</span> <span class="title function_">wait</span><span class="params">(<span class="type">int</span> *status)</span>;</span><br></pre></td></tr></table></figure>
<p>参数 status 保存着子进程退出时的一些状态（包括 task_struct、thread_info及内核栈等）它是一个指向 int 类型的指针；<br>如果不在意子进程的结束状态值，只想把这个僵尸进程消灭掉（实际上，大多数时候都是这样做的），则可以将这个参数设为 NULL。</p>
</li>
</ul>
<p>关于 status参数比较复杂，可以参考这里<br><a target="_blank" rel="noopener" href="https://www.ibm.com/developerworks/cn/linux/kernel/syscall/part3/index.html">传送门</a></p>
<ul>
<li>返回值<br>如果 wait() 调用成功，则会返回被收集子进程的进程ID；如果被调用进程没有子进程，则调用失败，返回 -1</li>
</ul>
<h3 id="waitpid"><a href="#waitpid" class="headerlink" title="waitpid"></a>waitpid</h3><ul>
<li><p>函数原型：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">pid_t</span> <span class="title function_">waitpid</span><span class="params">(<span class="type">pid_t</span> pid,<span class="type">int</span> *status,<span class="type">int</span> options)</span>;</span><br></pre></td></tr></table></figure>
<p>waitpid() 函数的功能与 wait() 的功能类似，不过，它比 wait() 函数多了两个参数：</p>
</li>
<li><p>1）参数 pid 为欲等待的子进程的识别码：<br>pid &lt; -1 ：等待进程组 ID 为 pid 绝对值的进程组中的任何子进程；<br>pid &#x3D; -1 ：等待任何子进程，此时 waitpid() 相当于 wait()。实际上，wait()就是 pid &#x3D; -1、options &#x3D; 0 的waitpid()， 且有：<br>pid &#x3D; 0 ：等待进程组 ID 与当前进程相同的任何子进程（也就是等待同一个进程组中的任何子进程）；<br>pid &gt; 0 ：等待任何子进程 ID 为 pid 的子进程，只要指定的子进程还没有结束，waitpid() 就会一直等下去。</p>
</li>
<li><p>2）参数 options 提供一些额外的选项来控制 waitpid()：<br>WNOHANG：如果没有任何已经结束了的子进程，则马上返回，不等待；<br>WUNTRACED：如果子进程进入暂停执行的情况，则马上返回，但结束状态不予理会；<br>也可以将这两个选项组合起来使用，使用 OR 操作。如果不想使用这两个选项，也可以直接把 options 设为 0 </p>
</li>
<li><p>3）waitpid() 的返回值，有三种：<br>a）正常返回时，waitpid() 返回收集到的子进程的PID；<br>b）如果设置了 WNOHANG，而调用 waitpid() 时，没有发现已退出的子进程可收集，则返回0；<br>c）如果调用出错，则返回 -1，这时erron 会被设置为相应的值以指示错误所在。（当 pid 所指示的子进程不错在，或此进程存在，但不是调用进程的子进程， waitpid() 就会返回出错，这时 erron 被设置为 ECHILD）</p>
</li>
</ul>
<h3 id="wait3-x2F-wait4"><a href="#wait3-x2F-wait4" class="headerlink" title="wait3&#x2F;wait4"></a>wait3&#x2F;wait4</h3><p>函数原型</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/tpyes.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/wait.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">pid_t</span> <span class="title function_">wait3</span><span class="params">(<span class="type">int</span> *status,<span class="type">int</span> options,<span class="keyword">struct</span> rusage *rusage)</span>;</span><br><span class="line"><span class="type">pid_t</span> <span class="title function_">wait4</span><span class="params">(<span class="type">pid_t</span> pid,<span class="type">int</span> *status,<span class="type">int</span> options,<span class="keyword">struct</span> rusage *rusage)</span>;</span><br></pre></td></tr></table></figure>
<p>wait3() 和 wait4() 函数除了可以获得子进程状态信息外，还可以获得子进程的资源使用信息，这些信息是通过参数 <strong>rusage</strong> 得到的。<br>而 wait3() 与 wait4() 之间的区别是，wait3() 等待所有进程，而 wait4() 可以根据 pid 的值选择要等待的子进程。<br>参数 pid 的意义与 waitpid() 函数的一样。</p>
<p>其中，需要注意的是，参数rusage所指向的结构中返回终止子进程的资源使用情况。其中包括进程使用的CPU时间总量以及内存管理的统计数据。<br>如下，为它的结构定义：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rusage</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">timeval</span> <span class="title">ru_utime</span>;</span> <span class="comment">/* user CPU time used */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">timeval</span> <span class="title">ru_stime</span>;</span> <span class="comment">/* system CPU time used */</span></span><br><span class="line">    <span class="type">long</span>   ru_maxrss;        <span class="comment">/* maximum resident set size */</span></span><br><span class="line">    <span class="type">long</span>   ru_ixrss;         <span class="comment">/* integral shared memory size */</span></span><br><span class="line">    <span class="type">long</span>   ru_idrss;         <span class="comment">/* integral unshared data size */</span></span><br><span class="line">    <span class="type">long</span>   ru_isrss;         <span class="comment">/* integral unshared stack size */</span></span><br><span class="line">    <span class="type">long</span>   ru_minflt;        <span class="comment">/* page reclaims (soft page faults) */</span></span><br><span class="line">    <span class="type">long</span>   ru_majflt;        <span class="comment">/* page faults (hard page faults) */</span></span><br><span class="line">    <span class="type">long</span>   ru_nswap;         <span class="comment">/* swaps */</span></span><br><span class="line">    <span class="type">long</span>   ru_inblock;       <span class="comment">/* block input operations */</span></span><br><span class="line">    <span class="type">long</span>   ru_oublock;       <span class="comment">/* block output operations */</span></span><br><span class="line">    <span class="type">long</span>   ru_msgsnd;        <span class="comment">/* IPC messages sent */</span></span><br><span class="line">    <span class="type">long</span>   ru_msgrcv;        <span class="comment">/* IPC messages received */</span></span><br><span class="line">    <span class="type">long</span>   ru_nsignals;      <span class="comment">/* signals received */</span></span><br><span class="line">    <span class="type">long</span>   ru_nvcsw;         <span class="comment">/* voluntary context switches */</span></span><br><span class="line">    <span class="type">long</span>   ru_nivcsw;        <span class="comment">/* involuntary context switches */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>其中比较重要的三项：</p>
<ol>
<li>timeval ru_utime; &#x2F;* user CPU time used *&#x2F;        用户态CPU使用时间</li>
<li>timeval ru_stime; &#x2F;* system CPU time used *&#x2F;      内核态CPU使用时间</li>
<li>ru_maxrss;        &#x2F;* maximum resident set size *&#x2F; 最大驻留集</li>
</ol>
<p>还可以shell中使用</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">man getrusage</span><br></pre></td></tr></table></figure>

<h3 id="如何使用int-status"><a href="#如何使用int-status" class="headerlink" title="如何使用int* status"></a>如何使用int* status</h3><p>如果参数status的值不是NULL，wait就会把子进程退出时的状态取出并存入其中，这指向整数值（int），<br>指出了子进程是正常退出还是被非正常结束的，以及正常结束时的返回值，或被哪一个信号结束的等信息。<br>由于这些信息被存放在<strong>一个整数的不同二进制位</strong>中，所以用常规的方法读取会非常麻烦，<br>于是就设计了一套专门的宏来完成这项工作，下面介绍一下其中最常用的几个。</p>
<p>请注意，下面的宏中的 status 虽然名字一样，这里的参数status并不同于wait中的参数<br>一个是指向整数的指针，而是那个指针所指向的整数，切记不要搞混。</p>
<h3 id="WIFEXITED-int-status"><a href="#WIFEXITED-int-status" class="headerlink" title="WIFEXITED(int status)"></a>WIFEXITED(int status)</h3><p>这个宏用来指出进程是否为正常退出的，如果是，它会返回一个非零值。</p>
<h3 id="WEXITSTATUS-status"><a href="#WEXITSTATUS-status" class="headerlink" title="WEXITSTATUS(status)"></a>WEXITSTATUS(status)</h3><p><strong>当WIFEXITED返回非零值时</strong>，可以用这个宏来提取<strong>子进程的返回值</strong>。<br>如果子进程调用exit(5)退出，WEXITSTATUS(status) 就会返回5；如果子进程调用exit(7)，WEXITSTATUS(status)就会返回7。<br>请注意，如果进程不是正常退出的，也就是 说，WIFEXITED返回0，这个值就毫无意义。</p>
<p>所以二者往往这样配合使用：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//正常退出判断</span></span><br><span class="line"><span class="keyword">if</span>(WIFEXITED(status))&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;child exit with %d\n&quot;</span>, WEXITSTATUS(status));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="WIFSIGNALED-status"><a href="#WIFSIGNALED-status" class="headerlink" title="WIFSIGNALED(status)"></a>WIFSIGNALED(status)</h3><p>这个宏来指出进程是否遇到未处理的信号而意外退出，如果是，返回非零0.</p>
<h3 id=""><a href="#" class="headerlink" title=""></a></h3><p><strong>当 WIFSIGNALED 返回非零值时</strong>，此时可通过WTERMSIG(status)获取使得<strong>进程退出的信号编号</strong></p>
<p>所以二者可以这样配合使用</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//因为某种信号中断获取状态</span></span><br><span class="line"><span class="keyword">if</span>(WIFSIGNALED(status))&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;child killed by %d\n&quot;</span>, WTERMSIG(status));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<ul>
<li>参考链接<br><a target="_blank" rel="noopener" href="https://man7.org/linux/man-pages/man2/wait4.2.html">wait4(2) — Linux manual page</a></li>
</ul>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/C/" rel="tag"># C</a>
              <a href="/tags/Linux/" rel="tag"># Linux</a>
              <a href="/tags/%E8%BF%9B%E7%A8%8B/" rel="tag"># 进程</a>
              <a href="/tags/%E7%BA%BF%E7%A8%8B/" rel="tag"># 线程</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/2021/11/20/Linux%E6%97%B6%E9%97%B4%E7%9B%B8%E5%85%B3%E5%BA%93%E5%87%BD%E6%95%B0/" rel="prev" title="Linux时间相关库函数">
                  <i class="fa fa-chevron-left"></i> Linux时间相关库函数
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/2021/11/20/Linux%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6%E7%9A%84%E5%AE%9E%E7%8E%B0/" rel="next" title="Linux文件描述符的使用与实现">
                  Linux文件描述符的使用与实现 <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">SongyangJi</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/muse/" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>
  <div class="sidebar-dimmer"></div>
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/schemes/muse.js"></script><script src="/js/next-boot.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>





  





</body>
</html>
